# 高级数据分析引擎
import logging
import pandas as pd
import numpy as np
from typing import Dict, List, Any, Optional, Tuple
from django.db.models import Count, Sum, Avg, Max, Min, Q
from django.utils import timezone
from datetime import datetime, timedelta
import json
import math

from .models import Asset, MaintenanceRecord, AssetCategory, Department
from .models_analytics import ReportTemplate, DataAnalysisTask, KPIMetric

logger = logging.getLogger(__name__)


class AnalyticsEngine:
    """高级数据分析引擎"""
    
    def __init__(self):
        self.data_sources = {
            'asset': Asset,
            'maintenance': MaintenanceRecord,
            'category': AssetCategory,
            'department': Department,
        }
    
    def execute_report(self, template: ReportTemplate, parameters: Dict = None) -> Dict:
        """执行报表生成"""
        
        try:
            # 获取数据
            data = self._get_report_data(template, parameters or {})
            
            # 处理数据
            processed_data = self._process_report_data(data, template)
            
            # 生成图表配置
            chart_config = self._generate_chart_config(processed_data, template)
            
            return {
                'success': True,
                'data': processed_data,
                'chart_config': chart_config,
                'metadata': {
                    'total_records': len(data) if isinstance(data, list) else data.count(),
                    'generated_at': timezone.now().isoformat(),
                    'parameters': parameters
                }
            }
            
        except Exception as e:
            logger.error(f"执行报表失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def _get_report_data(self, template: ReportTemplate, parameters: Dict) -> Any:
        """获取报表数据"""
        
        model_class = self.data_sources.get(template.data_source)
        if not model_class:
            raise ValueError(f"不支持的数据源: {template.data_source}")
        
        queryset = model_class.objects.all()
        query_config = template.query_config
        
        # 应用过滤条件
        filters = query_config.get('filters', [])
        for filter_item in filters:
            field = filter_item.get('field')
            operator = filter_item.get('operator')
            value = filter_item.get('value')
            
            # 支持参数替换
            if isinstance(value, str) and value.startswith('${') and value.endswith('}'):
                param_name = value[2:-1]
                value = parameters.get(param_name, value)
            
            # 构建查询条件
            if operator == 'equals':
                queryset = queryset.filter(**{field: value})
            elif operator == 'contains':
                queryset = queryset.filter(**{f"{field}__icontains": value})
            elif operator == 'greater_than':
                queryset = queryset.filter(**{f"{field}__gt": value})
            elif operator == 'less_than':
                queryset = queryset.filter(**{f"{field}__lt": value})
            elif operator == 'between':
                if isinstance(value, list) and len(value) == 2:
                    queryset = queryset.filter(**{f"{field}__range": value})
            elif operator == 'in':
                if isinstance(value, list):
                    queryset = queryset.filter(**{f"{field}__in": value})
        
        # 应用时间范围
        date_range = query_config.get('date_range')
        if date_range:
            date_field = date_range.get('field', 'created_at')
            start_date = date_range.get('start_date')
            end_date = date_range.get('end_date')
            
            if start_date and end_date:
                queryset = queryset.filter(**{f"{date_field}__range": [start_date, end_date]})
        
        # 应用聚合
        aggregation = query_config.get('aggregation')
        if aggregation:
            group_by = aggregation.get('group_by', [])
            metrics = aggregation.get('metrics', [])
            
            if group_by:
                # 分组聚合
                result = queryset.values(*group_by)
                
                for metric in metrics:
                    field = metric.get('field')
                    func = metric.get('function', 'count')
                    alias = metric.get('alias', f"{func}_{field}")
                    
                    if func == 'count':
                        result = result.annotate(**{alias: Count(field)})
                    elif func == 'sum':
                        result = result.annotate(**{alias: Sum(field)})
                    elif func == 'avg':
                        result = result.annotate(**{alias: Avg(field)})
                    elif func == 'max':
                        result = result.annotate(**{alias: Max(field)})
                    elif func == 'min':
                        result = result.annotate(**{alias: Min(field)})
                
                return list(result)
            else:
                # 简单聚合
                result = {}
                for metric in metrics:
                    field = metric.get('field')
                    func = metric.get('function', 'count')
                    alias = metric.get('alias', f"{func}_{field}")
                    
                    if func == 'count':
                        result[alias] = queryset.count()
                    elif func == 'sum':
                        result[alias] = queryset.aggregate(Sum(field))[f"{field}__sum"] or 0
                    elif func == 'avg':
                        result[alias] = queryset.aggregate(Avg(field))[f"{field}__avg"] or 0
                    elif func == 'max':
                        result[alias] = queryset.aggregate(Max(field))[f"{field}__max"]
                    elif func == 'min':
                        result[alias] = queryset.aggregate(Min(field))[f"{field}__min"]
                
                return result
        
        # 应用排序
        order_by = query_config.get('order_by', [])
        if order_by:
            queryset = queryset.order_by(*order_by)
        
        # 应用限制
        limit = query_config.get('limit')
        if limit:
            queryset = queryset[:limit]
        
        return queryset
    
    def _process_report_data(self, data, template: ReportTemplate) -> Dict:
        """处理报表数据"""
        
        report_config = template.report_config
        
        if isinstance(data, dict):
            # 单个聚合结果
            return {
                'type': 'single',
                'data': data
            }
        elif hasattr(data, 'values'):
            # QuerySet
            fields = report_config.get('fields', [])
            if fields:
                data_list = list(data.values(*fields))
            else:
                data_list = list(data.values())
            
            return {
                'type': 'list',
                'data': data_list,
                'count': len(data_list)
            }
        else:
            # 已经是列表
            return {
                'type': 'list',
                'data': data,
                'count': len(data)
            }
    
    def _generate_chart_config(self, processed_data: Dict, template: ReportTemplate) -> Dict:
        """生成图表配置"""
        
        chart_type = template.chart_type
        report_config = template.report_config
        
        if not chart_type:
            return {}
        
        data = processed_data.get('data', [])
        
        if chart_type == 'line':
            return self._generate_line_chart_config(data, report_config)
        elif chart_type == 'bar':
            return self._generate_bar_chart_config(data, report_config)
        elif chart_type == 'pie':
            return self._generate_pie_chart_config(data, report_config)
        elif chart_type == 'area':
            return self._generate_area_chart_config(data, report_config)
        elif chart_type == 'scatter':
            return self._generate_scatter_chart_config(data, report_config)
        elif chart_type == 'gauge':
            return self._generate_gauge_chart_config(data, report_config)
        else:
            return self._generate_default_chart_config(data, report_config)
    
    def _generate_line_chart_config(self, data: List, config: Dict) -> Dict:
        """生成折线图配置"""
        
        x_field = config.get('x_field', 'date')
        y_field = config.get('y_field', 'value')
        
        if isinstance(data, dict):
            # 单个数据点
            return {
                'type': 'line',
                'data': {
                    'labels': [x_field],
                    'datasets': [{
                        'label': y_field,
                        'data': [data.get(y_field, 0)],
                        'borderColor': 'rgb(75, 192, 192)',
                        'tension': 0.1
                    }]
                }
            }
        
        # 多个数据点
        labels = [item.get(x_field, '') for item in data]
        values = [item.get(y_field, 0) for item in data]
        
        return {
            'type': 'line',
            'data': {
                'labels': labels,
                'datasets': [{
                    'label': config.get('title', y_field),
                    'data': values,
                    'borderColor': 'rgb(75, 192, 192)',
                    'backgroundColor': 'rgba(75, 192, 192, 0.2)',
                    'tension': 0.1
                }]
            },
            'options': {
                'responsive': True,
                'plugins': {
                    'title': {
                        'display': True,
                        'text': config.get('title', '折线图')
                    }
                }
            }
        }
    
    def _generate_bar_chart_config(self, data: List, config: Dict) -> Dict:
        """生成柱状图配置"""
        
        x_field = config.get('x_field', 'category')
        y_field = config.get('y_field', 'count')
        
        if isinstance(data, dict):
            return {
                'type': 'bar',
                'data': {
                    'labels': [x_field],
                    'datasets': [{
                        'label': y_field,
                        'data': [data.get(y_field, 0)],
                        'backgroundColor': 'rgba(54, 162, 235, 0.5)'
                    }]
                }
            }
        
        labels = [str(item.get(x_field, '')) for item in data]
        values = [item.get(y_field, 0) for item in data]
        
        return {
            'type': 'bar',
            'data': {
                'labels': labels,
                'datasets': [{
                    'label': config.get('title', y_field),
                    'data': values,
                    'backgroundColor': 'rgba(54, 162, 235, 0.5)',
                    'borderColor': 'rgba(54, 162, 235, 1)',
                    'borderWidth': 1
                }]
            },
            'options': {
                'responsive': True,
                'plugins': {
                    'title': {
                        'display': True,
                        'text': config.get('title', '柱状图')
                    }
                },
                'scales': {
                    'y': {
                        'beginAtZero': True
                    }
                }
            }
        }
    
    def _generate_pie_chart_config(self, data: List, config: Dict) -> Dict:
        """生成饼图配置"""
        
        label_field = config.get('label_field', 'category')
        value_field = config.get('value_field', 'count')
        
        if isinstance(data, dict):
            return {
                'type': 'pie',
                'data': {
                    'labels': [label_field],
                    'datasets': [{
                        'data': [data.get(value_field, 0)],
                        'backgroundColor': ['rgba(255, 99, 132, 0.5)']
                    }]
                }
            }
        
        labels = [str(item.get(label_field, '')) for item in data]
        values = [item.get(value_field, 0) for item in data]
        
        # 生成颜色
        colors = [
            'rgba(255, 99, 132, 0.5)',
            'rgba(54, 162, 235, 0.5)',
            'rgba(255, 205, 86, 0.5)',
            'rgba(75, 192, 192, 0.5)',
            'rgba(153, 102, 255, 0.5)',
            'rgba(255, 159, 64, 0.5)'
        ]
        
        return {
            'type': 'pie',
            'data': {
                'labels': labels,
                'datasets': [{
                    'data': values,
                    'backgroundColor': colors[:len(values)]
                }]
            },
            'options': {
                'responsive': True,
                'plugins': {
                    'title': {
                        'display': True,
                        'text': config.get('title', '饼图')
                    },
                    'legend': {
                        'position': 'bottom'
                    }
                }
            }
        }
    
    def _generate_area_chart_config(self, data: List, config: Dict) -> Dict:
        """生成面积图配置"""
        
        line_config = self._generate_line_chart_config(data, config)
        line_config['type'] = 'line'
        
        # 修改为面积图
        if 'data' in line_config and 'datasets' in line_config['data']:
            for dataset in line_config['data']['datasets']:
                dataset['fill'] = True
        
        return line_config
    
    def _generate_scatter_chart_config(self, data: List, config: Dict) -> Dict:
        """生成散点图配置"""
        
        x_field = config.get('x_field', 'x')
        y_field = config.get('y_field', 'y')
        
        scatter_data = []
        for item in data:
            scatter_data.append({
                'x': item.get(x_field, 0),
                'y': item.get(y_field, 0)
            })
        
        return {
            'type': 'scatter',
            'data': {
                'datasets': [{
                    'label': config.get('title', '散点图'),
                    'data': scatter_data,
                    'backgroundColor': 'rgba(255, 99, 132, 0.5)'
                }]
            },
            'options': {
                'responsive': True,
                'plugins': {
                    'title': {
                        'display': True,
                        'text': config.get('title', '散点图')
                    }
                },
                'scales': {
                    'x': {
                        'type': 'linear',
                        'position': 'bottom'
                    }
                }
            }
        }
    
    def _generate_gauge_chart_config(self, data: Dict, config: Dict) -> Dict:
        """生成仪表盘配置"""
        
        value_field = config.get('value_field', 'value')
        max_value = config.get('max_value', 100)
        
        if isinstance(data, list) and data:
            value = data[0].get(value_field, 0)
        else:
            value = data.get(value_field, 0) if isinstance(data, dict) else 0
        
        return {
            'type': 'doughnut',
            'data': {
                'datasets': [{
                    'data': [value, max_value - value],
                    'backgroundColor': [
                        'rgba(75, 192, 192, 0.8)',
                        'rgba(200, 200, 200, 0.2)'
                    ],
                    'borderWidth': 0
                }]
            },
            'options': {
                'responsive': True,
                'cutout': '70%',
                'plugins': {
                    'title': {
                        'display': True,
                        'text': config.get('title', '仪表盘')
                    },
                    'legend': {
                        'display': False
                    }
                }
            }
        }
    
    def _generate_default_chart_config(self, data: Any, config: Dict) -> Dict:
        """生成默认图表配置"""
        
        return self._generate_bar_chart_config(data, config)
    
    def perform_trend_analysis(self, task: DataAnalysisTask) -> Dict:
        """执行趋势分析"""
        
        try:
            analysis_config = task.analysis_config
            data_source = task.data_source
            
            # 获取时间序列数据
            time_field = analysis_config.get('time_field', 'created_at')
            value_field = analysis_config.get('value_field', 'id')
            period = analysis_config.get('period', 'day')  # day, week, month
            
            model_class = self.data_sources.get(data_source)
            if not model_class:
                raise ValueError(f"不支持的数据源: {data_source}")
            
            # 构建时间范围查询
            end_date = timezone.now()
            if period == 'day':
                start_date = end_date - timedelta(days=30)
                date_format = '%Y-%m-%d'
            elif period == 'week':
                start_date = end_date - timedelta(weeks=12)
                date_format = '%Y-W%U'
            else:  # month
                start_date = end_date - timedelta(days=365)
                date_format = '%Y-%m'
            
            queryset = model_class.objects.filter(
                **{f"{time_field}__range": [start_date, end_date]}
            )
            
            # 按时间分组统计
            time_series_data = []
            current_date = start_date
            
            while current_date <= end_date:
                if period == 'day':
                    next_date = current_date + timedelta(days=1)
                elif period == 'week':
                    next_date = current_date + timedelta(weeks=1)
                else:  # month
                    next_date = current_date + timedelta(days=30)
                
                period_data = queryset.filter(
                    **{f"{time_field}__range": [current_date, next_date]}
                )
                
                if value_field == 'id':
                    value = period_data.count()
                else:
                    value = period_data.aggregate(Sum(value_field))[f"{value_field}__sum"] or 0
                
                time_series_data.append({
                    'date': current_date.strftime(date_format),
                    'value': value
                })
                
                current_date = next_date
            
            # 计算趋势
            values = [item['value'] for item in time_series_data]
            trend_analysis = self._calculate_trend(values)
            
            # 生成洞察
            insights = self._generate_trend_insights(time_series_data, trend_analysis)
            
            return {
                'success': True,
                'data': time_series_data,
                'trend': trend_analysis,
                'insights': insights
            }
            
        except Exception as e:
            logger.error(f"趋势分析失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def _calculate_trend(self, values: List[float]) -> Dict:
        """计算趋势"""
        
        if len(values) < 2:
            return {'direction': 'stable', 'slope': 0, 'correlation': 0}
        
        # 计算线性回归
        n = len(values)
        x = list(range(n))
        
        x_mean = sum(x) / n
        y_mean = sum(values) / n
        
        numerator = sum((x[i] - x_mean) * (values[i] - y_mean) for i in range(n))
        denominator = sum((x[i] - x_mean) ** 2 for i in range(n))
        
        if denominator == 0:
            slope = 0
        else:
            slope = numerator / denominator
        
        # 计算相关系数
        if n > 1:
            correlation = np.corrcoef(x, values)[0, 1]
            if math.isnan(correlation):
                correlation = 0
        else:
            correlation = 0
        
        # 判断趋势方向
        if abs(slope) < 0.1:
            direction = 'stable'
        elif slope > 0:
            direction = 'increasing'
        else:
            direction = 'decreasing'
        
        return {
            'direction': direction,
            'slope': slope,
            'correlation': correlation
        }
    
    def _generate_trend_insights(self, data: List, trend: Dict) -> List[Dict]:
        """生成趋势洞察"""
        
        insights = []
        
        # 趋势洞察
        direction = trend['direction']
        if direction == 'increasing':
            insights.append({
                'type': 'trend',
                'level': 'info',
                'title': '上升趋势',
                'description': '数据呈现上升趋势，增长态势良好'
            })
        elif direction == 'decreasing':
            insights.append({
                'type': 'trend',
                'level': 'warning',
                'title': '下降趋势',
                'description': '数据呈现下降趋势，需要关注'
            })
        else:
            insights.append({
                'type': 'trend',
                'level': 'info',
                'title': '稳定趋势',
                'description': '数据保持相对稳定'
            })
        
        # 异常值检测
        values = [item['value'] for item in data]
        if values:
            mean_value = sum(values) / len(values)
            std_value = np.std(values)
            
            for i, item in enumerate(data):
                if abs(item['value'] - mean_value) > 2 * std_value:
                    insights.append({
                        'type': 'anomaly',
                        'level': 'warning',
                        'title': '异常值检测',
                        'description': f"在 {item['date']} 检测到异常值: {item['value']}"
                    })
        
        return insights
    
    def update_kpi_metrics(self) -> Dict:
        """更新KPI指标"""
        
        results = {
            'updated_count': 0,
            'failed_count': 0,
            'errors': []
        }
        
        try:
            # 获取需要更新的KPI指标
            kpi_metrics = KPIMetric.objects.filter(
                is_active=True,
                auto_update=True
            )
            
            for kpi in kpi_metrics:
                try:
                    # 检查是否需要更新
                    if kpi.last_updated:
                        time_diff = timezone.now() - kpi.last_updated
                        if time_diff.total_seconds() < kpi.update_frequency * 60:
                            continue  # 还未到更新时间
                    
                    # 计算KPI值
                    new_value = self._calculate_kpi_value(kpi)
                    
                    # 更新KPI
                    kpi.previous_value = kpi.current_value
                    kpi.current_value = new_value
                    kpi.last_updated = timezone.now()
                    
                    # 计算趋势
                    if kpi.previous_value and kpi.current_value:
                        if kpi.current_value > kpi.previous_value:
                            kpi.trend = 'up'
                        elif kpi.current_value < kpi.previous_value:
                            kpi.trend = 'down'
                        else:
                            kpi.trend = 'stable'
                    
                    kpi.save()
                    results['updated_count'] += 1
                    
                except Exception as e:
                    error_msg = f"更新KPI {kpi.name} 失败: {str(e)}"
                    results['errors'].append(error_msg)
                    results['failed_count'] += 1
                    logger.error(error_msg)
            
            return results
            
        except Exception as e:
            logger.error(f"更新KPI指标失败: {e}")
            results['errors'].append(str(e))
            return results
    
    def _calculate_kpi_value(self, kpi: KPIMetric) -> float:
        """计算KPI值"""
        
        model_class = self.data_sources.get(kpi.data_source)
        if not model_class:
            raise ValueError(f"不支持的数据源: {kpi.data_source}")
        
        calculation_config = kpi.calculation_config
        queryset = model_class.objects.all()
        
        # 应用过滤条件
        filters = calculation_config.get('filters', [])
        for filter_item in filters:
            field = filter_item.get('field')
            operator = filter_item.get('operator')
            value = filter_item.get('value')
            
            if operator == 'equals':
                queryset = queryset.filter(**{field: value})
            elif operator == 'greater_than':
                queryset = queryset.filter(**{f"{field}__gt": value})
            # 可以添加更多操作符
        
        # 计算指标值
        metric_type = kpi.metric_type
        field = calculation_config.get('field', 'id')
        
        if metric_type == 'count':
            return float(queryset.count())
        elif metric_type == 'sum':
            result = queryset.aggregate(Sum(field))[f"{field}__sum"]
            return float(result or 0)
        elif metric_type == 'avg':
            result = queryset.aggregate(Avg(field))[f"{field}__avg"]
            return float(result or 0)
        elif metric_type == 'max':
            result = queryset.aggregate(Max(field))[f"{field}__max"]
            return float(result or 0)
        elif metric_type == 'min':
            result = queryset.aggregate(Min(field))[f"{field}__min"]
            return float(result or 0)
        else:
            return 0.0


# 创建全局实例
analytics_engine = AnalyticsEngine()